#include "tcpclient.h"

#include <QThread>

TcpClient::TcpClient(QObject* parent) : QObject(parent)
{
    m_socket = new QTcpSocket(this);
    m_status = Disconnected;
    m_dataReceived = false;

    connect(m_socket, &QTcpSocket::connected, this, &TcpClient::onConnected);
    connect(m_socket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected);
    connect(m_socket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);
    connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),
        this, &TcpClient::onErrorOccurred);
}

TcpClient::~TcpClient()
{
    disconnectFromServer();
    m_socket->deleteLater();
}

bool TcpClient::connectToServer(const QString& host, quint16 port, int timeoutMs)
{
    if (m_status == Connected) {
        return true;
    }

    setConnectionStatus(Connecting);
    m_socket->connectToHost(host, port);

    if (!m_socket->waitForConnected(timeoutMs)) {
        setConnectionStatus(Disconnected);
        return false;
    }

    return true;
}

void TcpClient::disconnectFromServer()
{
    if (m_status != Disconnected) {
        m_socket->disconnectFromHost();
        if (m_socket->state() != QAbstractSocket::UnconnectedState) {
            m_socket->waitForDisconnected(1000);
        }
    }
}

bool TcpClient::sendData(const QByteArray& data, int timeoutMs)
{
    if (m_status != Connected) {
        return false;
    }

    QMutexLocker locker(&m_mutex);
    clearReceiveBuffer();

    qint64 bytesWritten = m_socket->write(data);
    if (bytesWritten == -1) {
        return false;
    }

    if (!m_socket->waitForBytesWritten(timeoutMs)) {
        return false;
    }

    return true;
}

bool TcpClient::sendText(const QString& text, int timeoutMs)
{
    return sendData(text.toUtf8(), timeoutMs);
}

QByteArray TcpClient::receiveData(int timeoutMs)
{
    if (m_status != Connected) {
        return QByteArray();
    }

    QMutexLocker locker(&m_mutex);
    clearReceiveBuffer();

    // 如果已经有数据可用，直接返回
    if (m_socket->bytesAvailable() > 0) {
        return m_socket->readAll();
    }

    // 等待数据到达
    m_dataReceived = false;
    if (!m_waitCondition.wait(&m_mutex, timeoutMs) || !m_dataReceived) {
        return QByteArray();
    }

    return m_receivedData;
}

QString TcpClient::receiveText(int timeoutMs)
{
    QByteArray data = receiveData(timeoutMs);
    return QString::fromUtf8(data);
}

QByteArray TcpClient::sendAndReceive(const QByteArray& data, int timeoutMs)
{
    if (!sendData(data, timeoutMs)) {
        return QByteArray();
    }
    return receiveData(timeoutMs);
}

QString TcpClient::sendTextAndReceive(const QString& text, int timeoutMs)
{
    QByteArray data = sendAndReceive(text.toUtf8(), timeoutMs);
    return QString::fromUtf8(data);
}

void TcpClient::sendDataAsync(const QByteArray& data)
{
    if (m_status != Connected) {
        return;
    }

    m_socket->write(data);
}

void TcpClient::sendTextAsync(const QString& text)
{
    sendDataAsync(text.toUtf8());
}

bool TcpClient::isConnected() const
{
    return m_status == Connected;
}

TcpClient::ConnectionStatus TcpClient::connectionStatus() const
{
    return m_status;
}

QString TcpClient::errorString() const
{
    return m_socket->errorString();
}

void TcpClient::onConnected()
{
    setConnectionStatus(Connected);
}

void TcpClient::onDisconnected()
{
    setConnectionStatus(Disconnected);
}

void TcpClient::onReadyRead()
{
    QMutexLocker locker(&m_mutex);
    m_receivedData = m_socket->readAll();
    m_dataReceived = true;
    m_waitCondition.wakeAll();

    // 发出异步接收信号
    emit dataReceived(m_receivedData);
    emit textReceived(QString::fromUtf8(m_receivedData));
}

void TcpClient::onErrorOccurred(QAbstractSocket::SocketError error)
{
    Q_UNUSED(error);
    emit errorOccurred(m_socket->errorString());
}

void TcpClient::setConnectionStatus(ConnectionStatus status)
{
    if (m_status != status) {
        m_status = status;
        emit connectionStatusChanged(m_status);
    }
}

void TcpClient::clearReceiveBuffer()
{
    m_receivedData.clear();
    m_dataReceived = false;
    if (m_socket->bytesAvailable() > 0) {
        m_socket->readAll(); // 清空缓冲区
    }
}